package me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor1.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.minbearwcs.dao.storage.inf.LargeStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.SmallStorageDao;
import me.zhengjie.minbearwcs.dao.storage.inf.StorageDao;
import me.zhengjie.minbearwcs.entity.DTO.transfer.Tuple;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.SmallStorage;
import me.zhengjie.minbearwcs.entity.PO.wcs.storage.type.StorageType;
import me.zhengjie.minbearwcs.serivce.mission.storageProcessor.locker.Floor1.Storage1FLocker;
import org.apache.xmlbeans.impl.regex.REUtil;
import org.springframework.stereotype.Component;

import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


@Slf4j
@Component
@RequiredArgsConstructor
public class Storage1FLockerImpl implements Storage1FLocker {

    private final StorageDao storageDao;
    private final SmallStorageDao smallStorageDao;
    private final LargeStorageDao largeStorageDao;

    @Override
    public synchronized Tuple<String> lockWharfStorage(String palletCode, String logisticsCompanyCode) {
        String largeStorageCode = largeStorageDao.selectLargeStorageCodeByLogisticsCompany(logisticsCompanyCode);
        boolean isNullLargeStorage = false;
        if (largeStorageCode == null) {
            largeStorageCode = largeStorageDao.selectNullLogisticsCompanyByStorageType(StorageType.WHARF_1F);
            if (largeStorageCode == null) return Tuple.tuple(null, false);
            isNullLargeStorage = true;
        }

        List<String> canStorageMedium = storageDao.selectSingleEnterEmptyByLargeStorage(largeStorageCode);

        if (canStorageMedium.isEmpty()) {
            canStorageMedium = storageDao.selectSingleEnterEmpty(StorageType.STORAGE_AREA_4F);
            if (canStorageMedium.isEmpty()) return Tuple.tuple(null, false);
        }

        SmallStorage resultStorage = null;

        out:
        for (String mediumCode : canStorageMedium) {
            List<SmallStorage> smallStorageList = smallStorageDao.selectSmallStorageByMediunStorage(mediumCode);

            if (smallStorageList.isEmpty()) continue;

            if (smallStorageList.size() == 1) {
                resultStorage = smallStorageList.get(0);
                break;
            }

            // 判断中储位有没有开始人工取货
            List<Integer> emptyColList = smallStorageList.stream()
                    .filter(a -> a.getPalletCode() == null &&
                            a.getInboundFreezePallet() == null &&
                            a.getOutboundFreezePallet() == null)
                    .map(SmallStorage::getColumnNum)
                    .sorted(Integer::compareTo)
                    .collect(Collectors.toList());

            for (int i = emptyColList.size() - 1; i > 0; i--) {
                if (emptyColList.get(i) - emptyColList.get(i - 1) > 1) continue out;
            }


            SmallStorage firstSmall = smallStorageList.get(0);

            if (firstSmall.getIsEntrance() == 1) {
                Optional<SmallStorage> optional = smallStorageList.stream()
                        .filter(a -> a.getPalletCode() == null &&
                                a.getInboundFreezePallet() == null &&
                                a.getOutboundFreezePallet() == null)
                        .max(Comparator.comparingInt(SmallStorage::getColumnNum));
                if (optional.isPresent()) {
                    resultStorage = optional.get();
                    break;
                }
            } else {
                Optional<SmallStorage> optional = smallStorageList.stream()
                        .filter(a -> a.getPalletCode() == null &&
                                a.getInboundFreezePallet() == null &&
                                a.getOutboundFreezePallet() == null)
                        .min(Comparator.comparingInt(SmallStorage::getColumnNum));
                if (optional.isPresent()) {
                    resultStorage = optional.get();
                    break;
                }
            }
        }

        if (resultStorage == null) {
            return Tuple.tuple(null, false);
        } else {
            if (isNullLargeStorage) {
                largeStorageDao.updateLogisticsCompanyByLargeStorage(largeStorageCode, logisticsCompanyCode);
            }
            smallStorageDao.updateInboundFreezePallet(resultStorage.getId(), palletCode);
            return Tuple.tuple(resultStorage.getSmallStorageCode(), true);
        }

    }

    @Override
    public synchronized Tuple<String> lockLiftExitStorage(String palletCode) {
        String storage = storageDao.selectEmptyMediumStorageByStorageType(StorageType.LIFT_EXIT_1F);
        if (storage == null) {
            return Tuple.tuple(null, false);
        } else {
            smallStorageDao.updateInboundFreezePallet(storage, palletCode);
            return Tuple.tuple(storage, true);
        }
    }
}
